#include <jni.h>
#include <android/asset_manager_jni.h>
#include <android/asset_manager.h>
#include <GLES3/gl31.h>
#include <android/log.h>
#include <malloc.h>

using namespace std;
#define TAG "opengl_native"

#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)) // 定义LOGD类型
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, TAG ,__VA_ARGS__)) // 定义LOGW类型
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)) // 定义LOGE类型
#define LOGF(...) ((void)__android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)) // 定义LOGF类型

jint g_width, g_height;
GLuint g_program;
AAssetManager *g_manager = nullptr;

GLuint aPositionHandler;
GLuint aColorHandler;

float vertexArray[] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f, 0.5f, 0.0f
};
float colorArray[] = {
        0.5f, 1.0f, 0.0f, 0.0f,
        0.5f, 1.0f, 0.6f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f
};

//获取本地代码
char *loadLocationShaderSrc(AAssetManager *manager, const char *resFilePath) {
    LOGE("loadLocationShaderSrc start");
    if (manager == nullptr) return nullptr;
    AAsset *pAsset;
    off_t size;
    int lengthBuffer;
    char *byteBuffer = nullptr;
    pAsset = AAssetManager_open(manager, resFilePath, AASSET_MODE_UNKNOWN);
    size = AAsset_getLength(pAsset);
    byteBuffer = (char *) malloc(size + 1);
    byteBuffer[size] = '\0';
    lengthBuffer = AAsset_read(pAsset, byteBuffer, size);
    LOGE("loadLocationShaderSrc length");
    LOGE("%s\n", byteBuffer);
    AAsset_close(pAsset);
    LOGE("loadLocationShaderSrc end");
    return byteBuffer;
}

GLuint loadShader(GLenum TYPE, const char *shaderSrc) {
    LOGE("loadShader start");
    GLuint shaderHandle = glCreateShader(TYPE);
    glShaderSource(shaderHandle, 1, &shaderSrc, 0);
    glCompileShader(shaderHandle);
    GLint compileSuccess;
    glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
    if (compileSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
        messages[255]='\0';
        LOGE("loadShader Compile Error:");
        LOGE("%s",(char*)messages);
    }
    LOGE("loadShader end");
    return shaderHandle;

}

extern "C" {

JNIEXPORT void JNICALL
Java_com_example_opengldemo_ndk_MyNDKView_glesInit(
        JNIEnv *env,
        jobject instance) {
    LOGE("glesInit start");
    char *vertexSrc = loadLocationShaderSrc(g_manager, "vertex.glsl");
    char *fragmentSrc = loadLocationShaderSrc(g_manager, "fragment.glsl");
    GLuint vertexHandler = loadShader(GL_VERTEX_SHADER, vertexSrc);
    GLuint fragmentHandler = loadShader(GL_FRAGMENT_SHADER, fragmentSrc);
    GLuint program = glCreateProgram();
    glAttachShader(program, vertexHandler);
    glAttachShader(program, fragmentHandler);
    glLinkProgram(program);
    GLint linkSuccess;
    glGetProgramiv(program, GL_LINK_STATUS, &linkSuccess);
    if (linkSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
        messages[255] = '\0';
        LOGE("glesInit Shader Link Error:");
        LOGE("%s", (char *) messages);
        glDeleteProgram(program);
        return;

    }
    g_program = program;
    glClearColor(0.3f, 0.3f, 0.7f, 1.0f);

    aPositionHandler = (GLuint) glGetAttribLocation(program, "aPosition");
    aColorHandler = (GLuint) glGetAttribLocation(program, "aColor");
    LOGE("glesInit end");
}


JNIEXPORT void JNICALL
Java_com_example_opengldemo_ndk_MyNDKView_glesResize(
        JNIEnv *env,
        jobject instance,
        jint width,
        jint height) {
    LOGE("glesResize start");
    g_height = height;
    g_width = width;
    float d = (float) g_width / g_height;
    glViewport(0, 0, g_width, g_height);
    LOGE("glesResize end");

}


JNIEXPORT void JNICALL
Java_com_example_opengldemo_ndk_MyNDKView_glesRenderer(
        JNIEnv *env,
        jobject instance) {
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    glUseProgram(g_program);
    glVertexAttribPointer(aPositionHandler, 3, GL_FLOAT, GL_FALSE, 3 * 4, vertexArray);
    glVertexAttribPointer(aColorHandler, 4, GL_FLOAT, GL_FALSE, 4 * 4, colorArray);
    glEnableVertexAttribArray(aPositionHandler);
    glEnableVertexAttribArray(aColorHandler);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glDisableVertexAttribArray(aColorHandler);
    glDisableVertexAttribArray(aPositionHandler);
}

JNIEXPORT void JNICALL
Java_com_example_opengldemo_ndk_MyNDKView_loadAssetManager(
        JNIEnv *env,
        jobject instance,
        jobject manager) {
    if (env && manager) {
        LOGE("loadAssetManager env and manager is good");
        g_manager = AAssetManager_fromJava(env, manager);
        if (g_manager == nullptr) {
            LOGE("loadAssetManager manager is null");
        } else {
            LOGE("loadAssetManager manager is good");
        }
    } else {
        LOGE("loadAssetManager env or manager is null");
    }
}
}